; *******************************************************************
; * exp2_3.asm
; * LLP STUDIO Chen Zhepeng
; * V1.0
; * 2023-11-10
; * 上电时8个LED全亮，按下K1（#）时，LED灯交替输出55H和AAH，每0.5 s交替输出一次
; * 按下K2（÷）时，LED灯按二进制加规律从00H开始输出数据，每过0.5 s输出数据增1，
; * 至FFH后从00H循环递增
; *******************************************************************

P4   DATA 0C0H
P6   DATA 0E8H
P7   DATA 0F8H
P4M1 DATA 0B3H
P4M0 DATA 0B4H
P6M1 DATA 0CBH
P6M0 DATA 0CCH
P7M1 DATA 0E1H
P7M0 DATA 0E2H
HC595_SI  BIT P4.4  ; 74HC595串行输入端
HC595_SCK BIT P4.2  ; 74HC595移位时钟输入
HC595_RCK BIT P4.3  ; 74HC595锁存时钟输入
key_number EQU R7  ; 按下按键的键值
led_state DATA 42H  ; 8个LED灯的状态

ORG 0000H
LJMP Main
ORG 0100H
Main:
; 设置P4.0推挽，其他准双向
MOV P4M0, #01H
MOV P4M1, #00H
; 设置P6.0为推挽输出
MOV P6M0, #0FFH
MOV P6M1, #00H
MOV P7M0, #00H
MOV P7M1, #00H
MOV SP, #80H
LCALL Hc595Off
CLR P4.0  ; 允许LED显示
MOV key_number, #0  ; 键码初值为0
MOV led_state, #00H
Loop:
MOV P6, led_state
LCALL MatrixKey
CJNE key_number, #0, Next
LJMP Loop  ; 没有按键按下，直接下一次扫描
Next:  ; 如果有按键按下
CJNE key_number, #15, K2Other
MOV P6, #0FFH  ; 暂关闭所有LED
MOV P7, #0FFH
CLR P7.0  ; 第4列置0
K1:
MOV P6, #55H
LCALL DELAY500MS
MOV P6, #0AAH
LCALL DELAY500MS
; 同时响应K2
JNB P7.7, K2
SJMP K1
;LJMP Loop
K2Other:
CJNE key_number, #16, Other
K2:
CLR P7.1  ; 第3列置0
MOV led_state, #00H
K2Loop:
INC led_state
LCALL DELAY500MS
MOV P6, led_state
JNB P7.7, K1
SJMP K2Loop
Other:  ; 如果不是15号按键（#）也不是16号按键（÷），其他按键无效，直接下一次扫描
LJMP Loop

; * @brief       矩阵键盘扫描获取键值
; * @param       无
; * @retval      key_number: 按下按键的键值
MatrixKey:
MOV key_number, #0
MOV P7, #0FFH
CLR P7.3  ; 第1列置0
JNB P7.4, Key1
JNB P7.5, Key5
JNB P7.6, key9
JNB P7.7, Key13
LJMP Column2
Key1:
LCALL DELAY20MS
JNB P7.4, $
LCALL DELAY20MS
MOV key_number, #1
RET
Key5:
LCALL DELAY20MS
JNB P7.5, $
LCALL DELAY20MS
MOV key_number, #5
RET
Key9:
LCALL DELAY20MS
JNB P7.6, $
LCALL DELAY20MS
MOV key_number, #9
RET
Key13:
LCALL DELAY20MS
JNB P7.7, $
LCALL DELAY20MS
MOV key_number, #13
RET
Column2:
MOV P7, #0FFH
CLR P7.2  ; 第2列置0
JNB P7.4, Key2
JNB P7.5, Key6
JNB P7.6, key10
JNB P7.7, Key14
LJMP Column3
Key2:
LCALL DELAY20MS
JNB P7.4, $
LCALL DELAY20MS
MOV key_number, #2
RET
Key6:
LCALL DELAY20MS
JNB P7.5, $
LCALL DELAY20MS
MOV key_number, #6
RET
Key10:
LCALL DELAY20MS
JNB P7.6, $
LCALL DELAY20MS
MOV key_number, #10
RET
Key14:
LCALL DELAY20MS
JNB P7.7, $
LCALL DELAY20MS
MOV key_number, #14
RET
Column3:
MOV P7, #0FFH
CLR P7.1  ; 第3列置0
JNB P7.4, Key3
JNB P7.5, Key7
JNB P7.6, key11
JNB P7.7, Key15
LJMP Column4
Key3:
LCALL DELAY20MS
JNB P7.4, $
LCALL DELAY20MS
MOV key_number, #3
RET
Key7:
LCALL DELAY20MS
JNB P7.5, $
LCALL DELAY20MS
MOV key_number, #7
RET
Key11:
LCALL DELAY20MS
JNB P7.6, $
LCALL DELAY20MS
MOV key_number, #11
RET
Key15:
LCALL DELAY20MS
JNB P7.7, $
LCALL DELAY20MS
MOV key_number, #15
RET
Column4:
MOV P7, #0FFH
CLR P7.0  ; 第4列置0
JNB P7.4, Key4
JNB P7.5, Key8
JNB P7.6, key12
JNB P7.7, Key16
RET
Key4:
LCALL DELAY20MS
JNB P7.4, $
LCALL DELAY20MS
MOV key_number, #4
RET
Key8:
LCALL DELAY20MS
JNB P7.5, $
LCALL DELAY20MS
MOV key_number, #8
RET
Key12:
LCALL DELAY20MS
JNB P7.6, $
LCALL DELAY20MS
MOV key_number, #12
RET
Key16:
LCALL DELAY20MS
JNB P7.7, $
LCALL DELAY20MS
MOV key_number, #16
RET

; * @brief       向74HC595D发送一个字节
; * @param       ACC: 要发送的字节数据（存放在累加器中）
; * @retval      无
Hc595SendByte:
PUSH 02H
MOV R2, #8
Hc595SendLoop:
RLC A
MOV HC595_SI, C
SETB HC595_SCK
CLR HC595_SCK
DJNZ R2, Hc595SendLoop
POP 02H
RET

; * @brief       关闭74HC595D
; * @param       无
; * @retval      无
Hc595Off:
PUSH ACC
; 输出点阵位码，关闭LED点阵
CLR A
LCALL Hc595SendByte
; 输出数码管位码，关闭数码管
CLR A
LCALL Hc595SendByte
CLR HC595_RCK
NOP
SETB HC595_RCK  ; 输入数据上升沿锁存到输出端
CLR HC595_RCK  ; 锁存输出数据
POP ACC
RET

DELAY20MS:			;@24.000MHz
	NOP
	PUSH	30H
	PUSH	31H
	PUSH	32H
	MOV		30H,#3
	MOV		31H,#112
	MOV		32H,#89
DelayLoop:
	DJNZ	32H,DelayLoop
	DJNZ	31H,DelayLoop
	DJNZ	30H,DelayLoop
	POP		32H
	POP		31H
	POP		30H
	RET

DELAY500MS:			;@24.000MHz
	NOP
	NOP
	PUSH	30H
	PUSH	31H
	PUSH	32H
	MOV		30H,#61
	MOV		31H,#225
	MOV		32H,#60
Delay500msLoop:
	DJNZ	32H,Delay500msLoop
	DJNZ	31H,Delay500msLoop
	DJNZ	30H,Delay500msLoop
	POP		32H
	POP		31H
	POP		30H
	RET


END